{
    "cells": [
        {
            "cell_type": "raw",
            "metadata": {
                "vscode": {
                    "languageId": "raw"
                }
            },
            "source": [
                "---\n",
                "title: Traits\n",
                "description: Define shared behavior for types.\n",
                "---"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "A _trait_ is a set of requirements that a type must implement. You can think of\n",
                "it as a contract: a type that _conforms_ to a trait guarantees that it \n",
                "implements all of the features of the trait.\n",
                "\n",
                "Traits are similar to Java _interfaces_, C++ _concepts_, Swift _protocols_, and\n",
                "Rust _traits_. If you're familiar with any of those features, Mojo traits solve\n",
                "the same basic problem.\n",
                "\n",
                "## Background\n",
                "\n",
                "In dynamically-typed languages like Python, you don't need to explicitly declare\n",
                "that two classes are similar. This is easiest to show by example:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "%%python\n",
                "class Duck:\n",
                "    def quack(self):\n",
                "        print(\"Quack.\")\n",
                "\n",
                "class StealthCow:\n",
                "    def quack(self):\n",
                "        print(\"Moo!\")\n",
                "\n",
                "def make_it_quack_python(maybe_a_duck):\n",
                "    try:\n",
                "        maybe_a_duck.quack()\n",
                "    except:\n",
                "        print(\"Not a duck.\")\n",
                "\n",
                "make_it_quack_python(Duck())\n",
                "make_it_quack_python(StealthCow())"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "The `Duck` and `StealthCow` classes aren't related in any way, but they both \n",
                "define a `quack()` method, so they work the same in the `make_it_quack()`\n",
                "function. This works because Python uses dynamic dispatch—it identifies the\n",
                "methods to call at runtime. So `make_it_quack_python()` doesn't care what types\n",
                "you're passing it, only the fact that they implement the `quack()` method.\n",
                "\n",
                "In a statically-typed environment, this approach doesn't work:\n",
                "[`fn` functions](/mojo/manual/functions.html#fn-functions) require you to\n",
                "specify the type of each argument. If you wanted to write this example in Mojo \n",
                "_without_ traits, you'd need to write a function overload for each input type.\n",
                "All of the examples from here on are in Mojo, so we'll just call the function\n",
                "`make_it_quack()` going forward."
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Quack\n",
                        "Moo!\n"
                    ]
                }
            ],
            "source": [
                "@value\n",
                "struct Duck:\n",
                "    fn quack(self):\n",
                "        print(\"Quack\")\n",
                "\n",
                "@value\n",
                "struct StealthCow:\n",
                "    fn quack(self):\n",
                "        print(\"Moo!\")\n",
                "\n",
                "fn make_it_quack(definitely_a_duck: Duck):\n",
                "    definitely_a_duck.quack()\n",
                "\n",
                "fn make_it_quack(not_a_duck: StealthCow):\n",
                "    not_a_duck.quack()\n",
                "\n",
                "make_it_quack(Duck())\n",
                "make_it_quack(StealthCow())"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "This isn't too bad with only two classes. But the more classes you want to\n",
                "support, the less practical this approach is.\n",
                "\n",
                "You might notice that the Mojo versions of `make_it_quack()` don't include the\n",
                "`try/except` statement. We don't need it because Mojo's static type checking\n",
                "ensures that you can only pass instances of `Duck` or `StealthCow` into the \n",
                "`make_it_quack()`function.\n",
                "\n",
                "## Using traits\n",
                "\n",
                "Traits solve this problem by letting you define a shared set of _behaviors_ that\n",
                "types can implement. Then you can write a function that depends on the trait,\n",
                "rather than individual types. As an example, let's update the `make_it_quack()`\n",
                "example using traits. The first step is defining a trait:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 3,
            "metadata": {},
            "outputs": [],
            "source": [
                "trait Quackable:\n",
                "    fn quack(self):\n",
                "        ..."
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "A trait looks a lot like a struct, except it's introduced by the `trait` \n",
                "keyword. Right now, a trait can only contain method signatures, and cannot\n",
                "include method implementations. Each method signature must be followed by\n",
                "three dots (`...`) to indicate that the method is unimplemented.\n",
                "\n",
                ":::note TODO\n",
                "\n",
                "In the future, we plan to support defining fields and default method\n",
                "implementations inside a trait. Right now, though, a trait can only declare\n",
                "method signatures.\n",
                "\n",
                ":::\n",
                "\n",
                "Next we create some structs that conform to the `Quackable` trait. To indicate\n",
                "that a struct conforms to a trait, include the trait name in parenthesis after\n",
                "the struct name. You can also include multiple traits, separated by commas. \n",
                "(If you're familiar with Python, this looks just like Python's inheritance\n",
                "syntax.)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "@value\n",
                "struct Duck(Quackable):\n",
                "    fn quack(self):\n",
                "        print(\"Quack\")\n",
                "\n",
                "@value\n",
                "struct StealthCow(Quackable):\n",
                "    fn quack(self):\n",
                "        print(\"Moo!\")"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "The struct needs to implement any methods that are declared in the trait. The \n",
                "compiler enforces conformance: if a struct says it conforms to a trait, it must\n",
                "implement everything required by the trait or the code won't compile.\n",
                "\n",
                "Finally, you can define a function that takes a `Quackable` like this:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 5,
            "metadata": {},
            "outputs": [],
            "source": [
                "fn make_it_quack[T: Quackable](maybe_a_duck: T):\n",
                "    maybe_a_duck.quack()"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "This syntax may look a little unfamiliar if you haven't dealt with Mojo\n",
                "[parameters](/mojo/manual/parameters/index.html) before. What this signature\n",
                "means is that `maybe_a_duck` is an argument of type `T`, where `T` is a type\n",
                "that must conform to the `Quackable` trait. TODO: This syntax is a little \n",
                "verbose, and we hope to make it more ergonomic in a future release.\n",
                "\n",
                "Using the method is simple enough:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 6,
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Quack\n",
                        "Moo!\n"
                    ]
                }
            ],
            "source": [
                "make_it_quack(Duck())\n",
                "make_it_quack(StealthCow())"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "Note that you don't need the square brackets when you call `make_it_quack()`: \n",
                "the compiler infers the type of the argument, and ensures the type has the\n",
                "required trait.\n",
                "\n",
                "One limitation of traits is that you can't add traits to existing types. For\n",
                "example, if you define a new `Numeric` trait, you can't add it to the standard\n",
                "library `Float64` and `Int` types. However, the standard library already\n",
                "includes a few traits, and we'll be adding more over time.\n",
                "\n",
                "### Traits can require static methods\n",
                "\n",
                "In addition to regular instance methods, traits can specify required static \n",
                "methods. \n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 7,
            "metadata": {},
            "outputs": [],
            "source": [
                "trait HasStaticMethod:\n",
                "    @staticmethod\n",
                "    fn do_stuff(): ...\n",
                "\n",
                "fn fun_with_traits[T: HasStaticMethod]():\n",
                "    T.do_stuff()"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "## Implicit trait conformance\n",
                "\n",
                "Mojo also supports _implicit_ trait conformance. That is, if a type implements\n",
                "all of the methods required for a trait, it's treated as conforming to the\n",
                "trait, even if it doesn't explicitly include the trait in its declaration:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "struct RubberDucky:\n",
                "    fn quack(self):\n",
                "        print(\"Squeak!\")\n",
                "\n",
                "make_it_quack(RubberDucky())"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "Implicit conformance can be handy if you're defining a trait and you want it to\n",
                "work with types that you don't control—such as types from the standard library,\n",
                "or a third-party library.\n",
                "\n",
                "However, we still strongly recommend explicit trait conformance wherever\n",
                "possible. This has two advantages:\n",
                "\n",
                "- Documentation. It makes it clear that the type conforms to the trait, without\n",
                "  having to scan all of its methods.\n",
                "\n",
                "- Future feature support. When default method implementations are added to\n",
                "  traits, they'll only work for types that explicitly conform to traits."
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "## Trait inheritance\n",
                "\n",
                "Traits can inherit from other traits. A trait that inherits from another trait\n",
                "includes all of the requirements declared by the parent trait. For example:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 8,
            "metadata": {},
            "outputs": [],
            "source": [
                "trait Animal:\n",
                "    fn make_sound(self):\n",
                "        ...\n",
                "\n",
                "# Bird inherits from Animal\n",
                "trait Bird(Animal):\n",
                "    fn fly(self):\n",
                "        ..."
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "Since `Bird` inherits from `Animal`, a struct that conforms to the `Bird` trait\n",
                "needs to implement **both** `make_sound()` and `fly()`. And since every `Bird`\n",
                "conforms to `Animal`, a struct that conforms to `Bird` can be passed to any\n",
                "function that requires an `Animal`.\n",
                "\n",
                "To inherit from multiple traits, add a comma-separated list of traits inside the \n",
                "parenthesis. For example, you could define a `NamedAnimal` trait that combines the\n",
                "requirements of the `Animal` trait and a new `Named` trait:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 9,
            "metadata": {},
            "outputs": [],
            "source": [
                "trait Named:\n",
                "    fn get_name(self) -> String:\n",
                "        ...\n",
                "\n",
                "trait NamedAnimal(Animal, Named):\n",
                "    pass"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "## Traits and lifecycle methods\n",
                "\n",
                "Traits can specify required \n",
                "[lifecycle methods](/mojo/manual/lifecycle/#lifecycles-and-lifetimes), including\n",
                "constructors, copy constructors and move constructors.\n",
                "\n",
                "For example, the following code creates a `MassProducible` trait. A \n",
                "`MassProducible` type has a default (no-argument) constructor and can be moved.\n",
                "It uses the built-in [`Movable`](/mojo/stdlib/builtin/value/Movable) trait,\n",
                "which requires the type to have a [move \n",
                "constructor](/mojo/manual/lifecycle/life.html#move-constructor).\n",
                "\n",
                "The `factory[]()` function returns a newly-constructed instance of a \n",
                "`MassProducible` type."
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 6,
            "metadata": {},
            "outputs": [],
            "source": [
                "trait DefaultConstructible:\n",
                "    fn __init__(inout self): ...\n",
                "\n",
                "trait MassProducible(DefaultConstructible, Movable):\n",
                "    pass\n",
                "\n",
                "fn factory[T: MassProducible]() -> T:\n",
                "    return T()\n",
                "\n",
                "struct Thing(MassProducible):\n",
                "    var id: Int\n",
                "\n",
                "    fn __init__(inout self):\n",
                "        self.id = 0\n",
                "\n",
                "    fn __moveinit__(inout self, owned existing: Self):\n",
                "        self.id = existing.id\n",
                "\n",
                "var thing = factory[Thing]()"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "Note that [`@register_passable(\"trivial\")`](/mojo/manual/decorators/register-passable.html#register_passabletrivial) \n",
                "types have restrictions on their lifecycle methods: they can't define copy or\n",
                "move constructors, because they don't require any custom logic.\n",
                "\n",
                "For the purpose of trait conformance, the compiler treats trivial types as\n",
                "copyable and movable."
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "\n",
                "\n",
                "## Built-in traits\n",
                "\n"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "The Mojo standard library currently includes a few traits. They're implemented\n",
                "by a number of standard library types, and you can also implement these on your\n",
                "own types:\n",
                "\n",
                "  - [`AnyType`](/mojo/stdlib/builtin/anytype/AnyType)\n",
                "  - [`Boolable`](/mojo/stdlib/builtin/bool/Boolable)\n",
                "  - [`CollectionElement`](/mojo/stdlib/builtin/value/CollectionElement)\n",
                "  - [`Copyable`](/mojo/stdlib/builtin/value/Copyable)\n",
                "  - [`Intable`](/mojo/stdlib/builtin/int/Intable)\n",
                "  - [`KeyElement`](/mojo/stdlib/collections/dict/KeyElement)\n",
                "  - [`Movable`](/mojo/stdlib/builtin/value/Movable)\n",
                "  - [`PathLike`](/mojo/stdlib/os/pathlike/PathLike)\n",
                "  - [`Sized`](/mojo/stdlib/builtin/len/Sized)\n",
                "  - [`Stringable`](/mojo/stdlib/builtin/str/Stringable)\n",
                "\n",
                "The API reference docs linked above include usage examples for each trait. The\n",
                "following sections discuss a few of these traits.\n",
                "\n",
                "### The `Sized` trait\n",
                "\n",
                "The [`Sized`](/mojo/stdlib/builtin/len/Sized) trait identifies types that\n",
                "have a measurable length, like strings and arrays. \n",
                "\n",
                "Specifically, `Sized` requires a type to implement the `__len__()` method. \n",
                "This trait is used by the built-in [`len()`](/mojo/stdlib/builtin/len/len) \n",
                "function. For example, if you're writing a custom list type, you could \n",
                "implement this trait so your type works with `len()`:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 8,
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "0\n"
                    ]
                }
            ],
            "source": [
                "struct MyList(Sized):\n",
                "    var size: Int\n",
                "    # ...\n",
                "\n",
                "    fn __init__(inout self):\n",
                "        self.size = 0\n",
                "\n",
                "    fn __len__(self) -> Int:\n",
                "        return self.size\n",
                "\n",
                "print(len(MyList()))"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "### The `Intable` and `Stringable` traits\n",
                "\n",
                "The [`Intable`](/mojo/stdlib/builtin/int/Intable) and \n",
                "[`Stringable`](/mojo/stdlib/builtin/str/Stringable) traits identify types\n",
                "that can be implicitly converted to `Int` and `String`, respectively. \n",
                "\n",
                "Any type that conforms to `Stringable` works with the built-in\n",
                "[`print()`](/mojo/stdlib/builtin/io/print) and \n",
                "[`str()`](/mojo/stdlib/builtin/str/str) functions:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 10,
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "This is a dog named Spot\n"
                    ]
                }
            ],
            "source": [
                "@value\n",
                "struct Pet(Stringable):\n",
                "    var name: String\n",
                "    var type: String\n",
                "\n",
                "    fn __str__(self) -> String:\n",
                "        return \"This is a \" + self.type + \" named \" + self.name\n",
                "\n",
                "var spot = Pet(\"Spot\", \"dog\")\n",
                "print(spot)"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "Similarly, an `Intable` type works with the built-in \n",
                "[`int`](/mojo/stdlib/builtin/int/int-function) function. You can find an example\n",
                "in the [`Intable` API reference](/mojo/stdlib/builtin/int/Intable)."
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "\n",
                "\n",
                "### The `AnyType` trait\n",
                "\n",
                "When building a generic container type, one challenge is knowing how to dispose\n",
                "of the contained items when the container is destroyed. Any type that \n",
                "dynamically allocates memory needs to supply a \n",
                "[destructor](/mojo/manual/lifecycle/death.html#destructor) (`__del__()` method)\n",
                "that must be called to free the allocated memory. But not all types have a \n",
                "destructor, and your Mojo code has no way to determine which is which.\n",
                "\n",
                "The [`AnyType`](/mojo/stdlib/builtin/anytype/AnyType) trait solves this\n",
                "issue: every trait implicitly inherits from `AnyType`, and all structs conform\n",
                "to `AnyType`, which guarantees that the type has a destructor. For types that \n",
                "don't have one, Mojo adds a no-op destructor. This means you can call the \n",
                "destructor on any type.\n",
                "\n",
                "This makes it possible to build generic collections without leaking memory. When\n",
                "the collection's destructor is called, it can safely call the destructors on\n",
                "every item it contains."
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "## Generic structs with traits\n",
                "\n",
                "You can also use traits when defining a generic container. A generic container\n",
                "is a container (for example, an array or hashmap) that can hold different data\n",
                "types. In a dynamic language like Python it's easy to add  different types of\n",
                "items to a container. But in a statically-typed environment the compiler needs\n",
                "to be able to identify the types at compile time. For example, if the container\n",
                "needs to copy a value, the compiler needs to verify that the type can be copied.\n",
                "\n",
                "The [`List`](/mojo/stdlib/collections/list.html) type is an example of a\n",
                "generic container. A single `List` can only hold a single type of data.\n",
                "For example, you can create a list of integer values like this:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "3  6  9  "
                    ]
                }
            ],
            "source": [
                "from collections import List\n",
                "\n",
                "var list = List[Int](1, 2, 3)\n",
                "for i in range(len(list)):\n",
                "    print(list[i], sep=\" \", end=\"\")"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "You can use traits to define requirements for elements that are stored in a\n",
                "container. For example, `List` requires elements that can be moved and\n",
                "copied. To store a struct in a `List`, the struct needs to conform to\n",
                "the `CollectionElement` trait, which requires a \n",
                "[copy constructor](/mojo/manual/lifecycle/life.html#copy-constructor) and a \n",
                "[move constructor](/mojo/manual/lifecycle/life.html#move-constructor).\n",
                "\n",
                "Building generic containers is an advanced topic. For an introduction, see the\n",
                "section on \n",
                "[parameterized structs](/mojo/manual/parameters/#parameterized-structs)."
            ]
        }
    ],
    "metadata": {
        "kernelspec": {
            "display_name": "Mojo",
            "language": "mojo",
            "name": "mojo-jupyter-kernel"
        },
        "language_info": {
            "codemirror_mode": {
                "name": "mojo"
            },
            "file_extension": ".mojo",
            "mimetype": "text/x-mojo",
            "name": "mojo"
        }
    },
    "nbformat": 4,
    "nbformat_minor": 2
}
